package com.foreverwin.mes.so.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.foreverwin.mes.common.constants.HandleBOConstants;
import com.foreverwin.mes.core.base.FrontPage;
import com.foreverwin.mes.core.exception.BusinessException;
import com.foreverwin.mes.core.utils.StringUtils;
import com.foreverwin.mes.meapi.enums.CustomFieldsConstant;
import com.foreverwin.mes.meapi.model.*;
import com.foreverwin.mes.meapi.service.*;
import com.foreverwin.mes.production.dto.ReleaseAndStartSfcDto;
import com.foreverwin.mes.production.dto.ReleaseAndStartSfcResponse;
import com.foreverwin.mes.production.service.SfcExService;
import com.foreverwin.mes.so.mapper.ShopOrderDispatchDetailMapper;
import com.foreverwin.mes.so.model.Recipe;
import com.foreverwin.mes.so.model.RecipeParam;
import com.foreverwin.mes.so.model.SfcSoDispRel;
import com.foreverwin.mes.so.model.ShopOrderDispatchDetail;
import com.foreverwin.mes.so.service.RecipeService;
import com.foreverwin.mes.so.service.ShopOrderDispatchDetailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 工单派工明细表 服务实现类
 * </p>
 *
 * @author Syngna
 * @since 2020-02-06
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ShopOrderDispatchDetailServiceImpl extends ServiceImpl<ShopOrderDispatchDetailMapper, ShopOrderDispatchDetail> implements ShopOrderDispatchDetailService {

    private final Logger logger = LoggerFactory.getLogger(ShopOrderDispatchDetailServiceImpl.class);

    @Autowired
    private ShopOrderDispatchDetailMapper shopOrderDispatchDetailMapper;

    @Autowired
    private RecipeService recipeService;

    @Autowired
    private BomService bomService;

    @Autowired
    private ShopOrderService shopOrderService;

    @Autowired
    private ItemService itemService;

    @Autowired
    private CustomFieldsService customFieldsService;

    @Autowired
    private SfcService sfcService;

    @Autowired
    private SfcExService sfcExService;

    @Autowired
    private SfcSoDispRelServiceImpl sfcSoDispRelService;

    @Override
    public Page<ShopOrderDispatchDetail> selectPage(FrontPage<ShopOrderDispatchDetail> frontPage, ShopOrderDispatchDetail shopOrderDispatchDetail) {
        EntityWrapper<ShopOrderDispatchDetail> queryWrapper = new EntityWrapper<>();
        queryWrapper.setEntity(shopOrderDispatchDetail);
        return super.selectPage(frontPage.getPagePlus(), queryWrapper);
    }

    @Override
    public List<ShopOrderDispatchDetail> selectList(ShopOrderDispatchDetail shopOrderDispatchDetail) {
        EntityWrapper<ShopOrderDispatchDetail> queryWrapper = new EntityWrapper<>();
        queryWrapper.setEntity(shopOrderDispatchDetail);
        return super.selectList(queryWrapper);
    }

    @Override
    public List<ShopOrderDispatchDetail> listByShopOrder(String site, String shopOrder) {
        return shopOrderDispatchDetailMapper.selectByShopOrder(site, shopOrder);
    }

    @Override
    public List<ShopOrderDispatchDetail> listVisibleByResource(String site, String resrce) {
        return shopOrderDispatchDetailMapper.selectVisibleByResource(site, resrce);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public String release(String site, String user, List<String> taskDetailHandleList) {
        List<ShopOrderDispatchDetail> shopOrderDispatchDetailList = shopOrderDispatchDetailMapper.selectByIds(taskDetailHandleList);
        if (shopOrderDispatchDetailList != null && shopOrderDispatchDetailList.size() > 0) {
            String resource = shopOrderDispatchDetailList.get(0).getResrce();
            CustomFields customFields = customFieldsService.getAttributeValue(StringUtils.genHandle(HandleBOConstants.RESOURCE_BO, site, resource), CustomFieldsConstant.KW_RESOURCE_INTEGRATION);
            if (customFields == null || !"Y".equalsIgnoreCase(customFields.getValue())) {
                throw BusinessException.build("ME设备编号【" + resource + "】无法集成设备，不需要下发任务");
            }
        }
        for (ShopOrderDispatchDetail shopOrderDispatchDetail : shopOrderDispatchDetailList) {
            if (ShopOrderDispatchDetail.STATUS_RELEASED.equals(shopOrderDispatchDetail.getStatus())) {
                throw BusinessException.build("任务【" + shopOrderDispatchDetail.getDispTaskChildNo() + "】已经是下发状态");
            }
        }
        // 下发配方和BOM，更新状态
        // new Thread(() -> sendAndUpdate(site, "1", shopOrderDispatchDetailList)).start();
        return sendAndUpdate(site, "1", shopOrderDispatchDetailList);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public String revert(String site, String user, List<String> taskDetailHandleList) {
        List<ShopOrderDispatchDetail> shopOrderDispatchDetailList = shopOrderDispatchDetailMapper.selectByIds(taskDetailHandleList);
        // 下发配方和BOM，更新状态
        for (ShopOrderDispatchDetail shopOrderDispatchDetail : shopOrderDispatchDetailList) {
            if (!ShopOrderDispatchDetail.STATUS_RELEASED.equals(shopOrderDispatchDetail.getStatus())) {
                throw BusinessException.build("任务【" + shopOrderDispatchDetail.getDispTaskChildNo() + "】当前状态不可撤销");
            }
        }
        // new Thread(() -> sendAndUpdate(site, "2", shopOrderDispatchDetailList)).start();
        return sendAndUpdate(site, "2", shopOrderDispatchDetailList);
    }

    /**
     * 生产批开始设备集成接口
     *
     * @param site
     * @param user
     * @param operation
     * @param resource
     * @param taskNo
     * @param lotNo
     */
    @Override
    public void sfcAutoStart(String site, String user, String operation, String resource, String taskNo, String lotNo) {
        List<ShopOrderDispatchDetail> shopOrderDispatchDetailList = this.selectList(new EntityWrapper<ShopOrderDispatchDetail>()
                .eq(ShopOrderDispatchDetail.SITE, site)
                .eq(ShopOrderDispatchDetail.DISP_TASK_CHILD_NO, taskNo));
        if (shopOrderDispatchDetailList.size() == 0) {
            throw BusinessException.build("任务号【" + taskNo + "】不存在");
        }
        ShopOrderDispatchDetail shopOrderDispatchDetail = shopOrderDispatchDetailList.get(0);
        if (StringUtils.isBlank(resource)) {
            resource = shopOrderDispatchDetail.getResrce();
        }
        ReleaseAndStartSfcDto releaseAndStartSfcDto = new ReleaseAndStartSfcDto();
        releaseAndStartSfcDto.setSite(site);
        releaseAndStartSfcDto.setUser(user);
        releaseAndStartSfcDto.setShopOrderBo(StringUtils.genHandle(HandleBOConstants.SHOP_ORDER_BO, site, shopOrderDispatchDetail.getShopOrder()));
        releaseAndStartSfcDto.setSfcBo(StringUtils.genHandle(HandleBOConstants.SFC_BO, site, lotNo));
        releaseAndStartSfcDto.setOperationBo(StringUtils.genHandle(HandleBOConstants.OPERATION_BO, site, operation, "#"));
        releaseAndStartSfcDto.setResourceBo(StringUtils.genHandle(HandleBOConstants.RESOURCE_BO, site, resource));
        releaseAndStartSfcDto.setQuantityToRelease(shopOrderDispatchDetail.getScheduleQty());
        releaseAndStartSfcDto.setReleaseAppointSfc(true);
        // 插入任务和生产批关联关系
        Sfc sfc = sfcService.selectById(releaseAndStartSfcDto.getSfcBo());
        if (sfc == null) {
            SfcSoDispRel sfcSoDispRel = new SfcSoDispRel();
            sfcSoDispRel.setSite(site);
            sfcSoDispRel.setResrce(resource);
            sfcSoDispRel.setSfc(lotNo);
            sfcSoDispRel.setLotNo(lotNo);
            sfcSoDispRel.setTaskNo(taskNo);
            sfcSoDispRel.setStatus("NEW");
            sfcSoDispRel.setCreator(user);
            sfcSoDispRel.setCreatedDateTime(new Date());
            sfcSoDispRelService.insert(sfcSoDispRel);
        }
        // 生产批下达并开始
        sfcExService.releaseAndStartSfc(releaseAndStartSfcDto);
    }

    /**
     * 生产批开始非设备集成接口
     *
     * @param site
     * @param user
     * @param operation
     * @param resource
     * @param taskOrSfcNo
     */
    @Override
    public List<String> sfcManualStart(String site, String user, String operation, String resource, String taskOrSfcNo) {
        String resourceBo = StringUtils.genHandle(HandleBOConstants.RESOURCE_BO, site, resource);
        String operationBo = StringUtils.genHandle(HandleBOConstants.OPERATION_BO, site, operation);
        /*Sfc sfc = sfcService.selectById(StringUtils.genHandle(HandleBOConstants.SFC_BO, site, taskOrSfcNo));
        if (sfc != null) {
            sfcExService.sfcStart(site, resourceBo, operationBo, sfc.getHandle());
            return Arrays.asList(sfc.getSfc());
        }*/
        List<ShopOrderDispatchDetail> shopOrderDispatchDetailList = this.selectList(new EntityWrapper<ShopOrderDispatchDetail>()
                .eq(ShopOrderDispatchDetail.SITE, site)
                .eq(ShopOrderDispatchDetail.DISP_TASK_CHILD_NO, taskOrSfcNo));
        if (shopOrderDispatchDetailList.size() == 0) {
            throw BusinessException.build("【" + taskOrSfcNo + "】不是任务号");
        }
        ShopOrderDispatchDetail shopOrderDispatchDetail = shopOrderDispatchDetailList.get(0);
        if (ShopOrderDispatchDetail.STATUS_RELEASED.equals(shopOrderDispatchDetail.getStatus())) {
            throw BusinessException.build("任务【" + taskOrSfcNo + "】已下发，不允许做开始动作");
        }
        if (StringUtils.isBlank(resource)) {
            resource = shopOrderDispatchDetail.getResrce();
        }
        ReleaseAndStartSfcDto releaseAndStartSfcDto = new ReleaseAndStartSfcDto();
        releaseAndStartSfcDto.setSite(site);
        releaseAndStartSfcDto.setUser(user);
        releaseAndStartSfcDto.setShopOrderBo(StringUtils.genHandle(HandleBOConstants.SHOP_ORDER_BO, site, shopOrderDispatchDetail.getShopOrder()));
        releaseAndStartSfcDto.setSfcBo(StringUtils.genHandle(HandleBOConstants.SFC_BO, site, taskOrSfcNo));
        releaseAndStartSfcDto.setOperationBo(StringUtils.genHandle(HandleBOConstants.OPERATION_BO, site, operation, "#"));
        releaseAndStartSfcDto.setResourceBo(StringUtils.genHandle(HandleBOConstants.RESOURCE_BO, site, resource));
        releaseAndStartSfcDto.setQuantityToRelease(shopOrderDispatchDetail.getScheduleQty());
        releaseAndStartSfcDto.setReleaseAppointSfc(true);
        // 生产批下达并开始
        ReleaseAndStartSfcResponse releaseAndStartSfcResponse = sfcExService.releaseAndStartSfc(releaseAndStartSfcDto);
        List<String> respSfcs = releaseAndStartSfcResponse.getReleasedSfcRefs();
        List<String> sfcNoList = new ArrayList<>();
        if(respSfcs != null && respSfcs.size() > 0) {
            for(String sfcBos : respSfcs) {
                String sfcNo = StringUtils.trimHandle(sfcBos);
                sfcNoList.add(sfcNo);
                // 插入任务和生产批关联关系
                SfcSoDispRel sfcSoDispRel = new SfcSoDispRel();
                sfcSoDispRel.setSite(site);
                sfcSoDispRel.setResrce(resource);
                sfcSoDispRel.setSfc(sfcNo);
                sfcSoDispRel.setLotNo(taskOrSfcNo);
                sfcSoDispRel.setTaskNo(taskOrSfcNo);
                sfcSoDispRel.setStatus("NEW");
                sfcSoDispRel.setCreator(user);
                sfcSoDispRel.setCreatedDateTime(new Date());
                sfcSoDispRelService.insert(sfcSoDispRel);
            }
        }
        return sfcNoList;
    }

    /**
     * 发送下达信息至设备
     *
     * @param site                        站点
     * @param mode                        模式（1:新增，2:修改，3:删除）
     * @param shopOrderDispatchDetailList
     */
    public String sendAndUpdate(String site, String mode, List<ShopOrderDispatchDetail> shopOrderDispatchDetailList) {
        StringBuilder sb = new StringBuilder();
        Map<String, String> recipeIdCache = new HashMap<>();
        Map<String, String> bomIdCache = new HashMap<>();
        Map<String, JSONArray> recipeInfoCache = new HashMap<>();
        Map<String, Map<String, JSONArray>> bomInfoCache = new HashMap<>();
        String resource = "";
        String resourceTaskSplit = "N";
        if (shopOrderDispatchDetailList.size() > 0) {
            resource = shopOrderDispatchDetailList.get(0).getResrce();
            CustomFields customFields = customFieldsService.getAttributeValue(StringUtils.genHandle(HandleBOConstants.RESOURCE_BO, site, resource), CustomFieldsConstant.KW_RESOURCE_TASK_SPLIT);
            resourceTaskSplit = customFields == null ? "N" : customFields.getValue();
        }
        for (ShopOrderDispatchDetail shopOrderDispatchDetail : shopOrderDispatchDetailList) {
            boolean failed = false;
            try {
                String item = StringUtils.trimHandle(shopOrderDispatchDetail.getItemBo());
                String shopOrder = shopOrderDispatchDetail.getShopOrder();
                String itemBo = shopOrderDispatchDetail.getItemBo();
                // recipe信息
                String recipeId;
                String recipeCacheKey = item + resource;
                JSONArray recipeInfo = new JSONArray();
                if (recipeInfoCache.containsKey(recipeCacheKey)) {
                    recipeInfo = recipeInfoCache.get(recipeCacheKey);
                    recipeId = recipeIdCache.get(recipeCacheKey);
                } else {
                    Recipe recipe = recipeService.getRecipeInfo(site, item, resource);
                    if(recipe != null) {
                        recipeId = recipe.getRecipe();
                        recipeInfo = buildRecipeInfo(recipe);
                        recipeIdCache.put(recipeCacheKey, recipeId);
                        recipeInfoCache.put(recipeCacheKey, recipeInfo);
                    } else {
                        recipeId = null;
                        recipeInfoCache.put(recipeCacheKey, new JSONArray());
                        recipeIdCache.put(recipeCacheKey, null);
                    }
                }
                // bom信息
                String bomId;
                String bomCacheKey = shopOrder + resource;
                Map<String, JSONArray> bomInfo = new HashMap<>();
                if (bomInfoCache.containsKey(bomCacheKey)) {
                    bomInfo = bomInfoCache.get(bomCacheKey);
                    bomId = bomIdCache.get(bomCacheKey);
                } else {
                    // 先找工单bom，再找物料bom
                    String bomBo = "";
                    ShopOrder shopOrderPo = shopOrderService.selectById(StringUtils.genHandle(HandleBOConstants.SHOP_ORDER_BO, site, shopOrder));
                    if (shopOrderPo != null) {
                        bomBo = shopOrderPo.getPlannedBomBo();
                    }
                    if (StringUtils.isBlank(bomBo) && StringUtils.notBlank(itemBo)) {
                        Item itemPo = itemService.selectById(itemBo);
                        if (itemPo != null) {
                            bomBo = itemPo.getBomBo();
                        }
                    }
                    if (StringUtils.isBlank(bomBo)) {
                        throw BusinessException.build("未找到任务【" + shopOrderDispatchDetail.getDispTaskChildNo() + "】工单【" + shopOrder + "】对应的物料清单");
                    }
                    Bom bom = bomService.getBomInfo(site, bomBo);
                    if (bom == null) {
                        throw BusinessException.build("任务【" + shopOrderDispatchDetail.getDispTaskChildNo() + "】工单【" + shopOrder + "】对应的物料清单【" + bomBo + "】不存在");
                    }
                    bomInfo = buildBomInfo(resourceTaskSplit, bom);
                    bomId = bom.getBom();
                    bomInfoCache.put(bomCacheKey, bomInfo);
                    bomIdCache.put(bomCacheKey, bomId);
                }
                for (Map.Entry<String, JSONArray> entry : bomInfo.entrySet()) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
                    Date now = new Date();
                    String resourceBatch = shopOrderDispatchDetail.getResourceBatch();
                    String batchNum = "";
                    if (!StringUtils.isBlank(resourceBatch)) {
                        BigDecimal[] bg = shopOrderDispatchDetail.getScheduleQty().divideAndRemainder(new BigDecimal(resourceBatch));
                        int count = bg[0].intValue();
                        if (bg[1].compareTo(BigDecimal.ZERO) > 0) {
                            count++;
                        }
                        batchNum = count + "";
                    }
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("MESSAGE_ID", "lot.info.download.process");
                    jsonObject.put("REQ_ID", StringUtils.createQUID());
                    jsonObject.put("SITE", site);
                    jsonObject.put("RESOURCE", resource);
                    jsonObject.put("SEND_TIME", simpleDateFormat.format(now));

                    jsonObject.put("SO", shopOrderDispatchDetail.getDispTaskChildNo());
                    jsonObject.put("LOT", "");
                    jsonObject.put("MODE", mode);
                    jsonObject.put("ITEM", StringUtils.trimHandle(shopOrderDispatchDetail.getItemBo()));
                    jsonObject.put("ITEM_DESC", shopOrderDispatchDetail.getItemDescription());
                    jsonObject.put("ITEM_VER", StringUtils.trimRevision(shopOrderDispatchDetail.getItemBo()));
                    jsonObject.put("QTY", shopOrderDispatchDetail.getScheduleQty());
                    jsonObject.put("BATCH_NUM", batchNum);
                    jsonObject.put("TO_STOCK", "");
                    jsonObject.put("RECIPE_ID", recipeId);
                    jsonObject.put("RECIPE_INFO", recipeInfo);
                    jsonObject.put("BOM_ID", bomId);

                    if ("MQ".equalsIgnoreCase(entry.getKey())) {
                        jsonObject.put("BOM_INFO", entry.getValue());
                        // TODO 发送消息至MQ，如果反馈结果为F，则更改状态为为FAILED
                    } else {
                        // TODO 发送消息至OPC， 如果反馈结果为F，则更改状态为为FAILED
                        jsonObject.put("BOM_INFO", entry.getValue());
                    }
                    logger.info("[lot.info.download.process] SEND: {}", jsonObject);
                }
            } catch (Exception e) {
                failed = true;
                // shopOrderDispatchDetail.setStatus(originStatus);
                // shopOrderDispatchDetail.setRecipeStatus(originRecipeStatus);
                String msg = StringUtils.isBlank(e.getMessage()) ? e.toString() : e.getMessage();
                shopOrderDispatchDetail.setMsg(msg.length() > 1024 ? msg.substring(0, 1024) : msg);
                sb.append(e.getMessage()).append("\n");
            }
            if(!failed) {
                shopOrderDispatchDetail.setStatus("2".equalsIgnoreCase(mode) ? ShopOrderDispatchDetail.STATUS_RELEASABLE : ShopOrderDispatchDetail.STATUS_RELEASED);
                shopOrderDispatchDetail.setRecipeStatus("2".equalsIgnoreCase(mode) ? ShopOrderDispatchDetail.STATUS_RELEASABLE : ShopOrderDispatchDetail.STATUS_RELEASED);
                shopOrderDispatchDetail.setModifiedDateTime(new Date());
                this.updateById(shopOrderDispatchDetail);
            }
        }
        return sb.toString();
    }

    /**
     * 组装接口配方信息
     *
     * @param recipe
     * @return
     */
    private JSONArray buildRecipeInfo(Recipe recipe) {
        JSONArray recipeParamList = new JSONArray();
        if (recipe.getRecipeParamList() == null) {
            recipe.setRecipeParamList(new ArrayList<>());
        }
        for (int i = 0; i < recipe.getRecipeParamList().size(); i++) {
            RecipeParam recipeParam = recipe.getRecipeParamList().get(i);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ID", i + 1);
            jsonObject.put("KEY", recipeParam.getParamName());
            jsonObject.put("VALUE", recipeParam.getParamValue());
            recipeParamList.add(jsonObject);
        }
        return recipeParamList;
    }

    private Map<String, JSONArray> buildBomInfo(String split, Bom bom) {
        Map<String, JSONArray> returnMap = new HashMap<>();
        if ("Y".equalsIgnoreCase(split)) {
            returnMap.put("MQ", new JSONArray());
            returnMap.put("OPC", new JSONArray());
        } else {
            returnMap.put("MQ", new JSONArray());
        }
        JSONArray boomComponentList = new JSONArray();
        List<BomComponent> bomComponentList = bom.getBomComponentList();
        if (bomComponentList == null || bomComponentList.size() == 0) {
            return returnMap;
        }
        for (BomComponent bomComponent : bomComponentList) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ID", bomComponent.getSequence());
            jsonObject.put("ITEM", StringUtils.trimHandle(bomComponent.getComponentGbo()));
            jsonObject.put("ITEM_DESC", StringUtils.trimHandle(bomComponent.getItemDescription()));
            jsonObject.put("ITEM_VER", StringUtils.trimRevision(bomComponent.getComponentGbo()));
            jsonObject.put("QTY", bomComponent.getQty());
            jsonObject.put("FROM_STOCK", "");
            // 大中料任务->OPC、小料任务->MQ
            String itemSize = bomComponent.getItemSize();
            if ("Y".equalsIgnoreCase(split)) {
                if ("G".equalsIgnoreCase(itemSize) || "M".equalsIgnoreCase(itemSize)) {
                    returnMap.get("OPC").add(jsonObject);
                } else if ("S".equalsIgnoreCase(itemSize)) {
                    returnMap.get("MQ").add(jsonObject);
                }
            } else {
                returnMap.get("MQ").add(jsonObject);
            }
        }
        return returnMap;
    }
}